package net.sf.nlp.ltag.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeSelectionModel;

import org.apache.log4j.Logger;

import net.sf.nlp.ltag.data.LTAGNode;
import net.sf.nlp.ltag.data.LTAGTree;

@SuppressWarnings("serial")
public class TreePanel extends JPanel implements ActionListener, MouseListener, ComponentListener
{
	private static Logger logger =  Logger.getLogger(TreePanel.class);
	private static final int SMALL_GRAPH_WIDTH = 100;
	private static final int SMALL_GRAPH_HEIGHT = 100;
	private static final int FLOW_LAYOUT_GAP = 5;
	
	private JPanel treePanel;
	private JPanel graphVizPanel;
	
	private JTree jTree;
	private String result;
	private JScrollPane graphView;
	private JScrollPane treeView;
	private JRadioButton treeRadioBtn;
	private JRadioButton graphRadioBtn;
	
	private List<LTAGTree> trees;
	private List<File> graphFiles;
	private List<JLabel> graphLabels = new ArrayList<JLabel>();
	private DefaultMutableTreeNode top;
	
	
	public TreePanel()
	{
		super(new GridLayout(1,0));
		
		init();
	}
	
	public void setTrees(List<LTAGTree> trees)
	{
		this.trees = trees;
		
		showTrees();
	}
	
	public void setGraphs(List<File> graphFiles)
	{
		this.graphFiles = graphFiles;
		
		showGraphs();
	}
	
	public void setResult(String result) {
		this.result = result;
	}

	private void init()
	{
		JPanel resultPanel = new JPanel();
		resultPanel.setLayout(new BorderLayout());
		
		addDisplayOptions(resultPanel);
		addDisplayTree(resultPanel);
		
        add(resultPanel);
	}
	
	private void addDisplayOptions(JPanel resultPanel)
	{
		JPanel optionPanel = new JPanel();
		optionPanel.setLayout(new FlowLayout());
		
		graphRadioBtn = new JRadioButton("GraphViz", true);
		treeRadioBtn = new JRadioButton("Tree");
		
		graphRadioBtn.addActionListener(this);
		treeRadioBtn.addActionListener(this);
		
		ButtonGroup btnGroup=new ButtonGroup(); 
		btnGroup.add(graphRadioBtn);
		btnGroup.add(treeRadioBtn);

		optionPanel.add(graphRadioBtn);
		optionPanel.add(treeRadioBtn);
		
		resultPanel.add(optionPanel, BorderLayout.NORTH);
	}
	
	private void addDisplayTree(JPanel resultPanel)
	{
		treePanel = new JPanel();
		treePanel.setLayout(new BorderLayout());
		
		resultPanel.add(treePanel, BorderLayout.CENTER);
		
		top = new DefaultMutableTreeNode("分析结果");
		jTree = new JTree(top);
		jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

		treeView = new JScrollPane(jTree);
        
        Dimension minimumSize = new Dimension(100, 500);
        treeView.setMinimumSize(minimumSize);
        treeView.setPreferredSize(new Dimension(1000, 600));

        graphVizPanel = new JPanel();
        FlowLayout flow = new FlowLayout(FlowLayout.LEFT);
        flow.setHgap(FLOW_LAYOUT_GAP);
        flow.setVgap(FLOW_LAYOUT_GAP);
        graphVizPanel.setLayout(flow);
        graphVizPanel.setMinimumSize(minimumSize);
        graphVizPanel.setPreferredSize(new Dimension(1000, 600));
        
        graphView = new JScrollPane(graphVizPanel);
        graphView.setMinimumSize(minimumSize);
        graphView.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        graphView.addComponentListener(this);
        displayResult();
	}
	
	private void displayResult()
	{
		treePanel.removeAll();
		
		 if (graphRadioBtn.isSelected())
			 treePanel.add(graphView, BorderLayout.CENTER);
		 else if (treeRadioBtn.isSelected())
			 treePanel.add(treeView, BorderLayout.CENTER);
		 
		 treePanel.updateUI();
	}
	
	private void showTrees() 
	{
		top.removeAllChildren();
		
		if (trees == null)
			return;
		
		StringBuffer sb = new StringBuffer("分析结果-(" + trees.size() + ")");
		
		if (result != null)
			sb.append(" [").append(result).append("]");
		
		top.setUserObject(sb.toString());
		
		for (LTAGTree tree : trees)
        {
			LTAGNode root = tree.getRoot();
			
			addNode(root, top); 
        }
		
		jTree.updateUI();
	}
	
	private void addNode(LTAGNode node, DefaultMutableTreeNode top) 
	{
		DefaultMutableTreeNode jNode = new DefaultMutableTreeNode(node.toSimpleString());
		
		top.add(jNode);
		
		if (node.getChildren() == null)
			return;
		
		for (LTAGNode child : node.getChildren())
			addNode(child, jNode);
    }

	private void drawGraphs()
	{
		int width = graphView.getWidth() - 20;
		int number = width / (SMALL_GRAPH_WIDTH + FLOW_LAYOUT_GAP);
		int row = graphLabels.size()/ number + 1;
		int height = (SMALL_GRAPH_HEIGHT + FLOW_LAYOUT_GAP) * row;
		
		height += SMALL_GRAPH_HEIGHT;
		
		graphVizPanel.setPreferredSize(new Dimension(width, height));
		graphVizPanel.repaint();
	}
	
	private void showGraphs()
	{
		graphVizPanel.removeAll();
		graphLabels.clear();
		
		if (graphFiles != null)
		{
			for (int i = 0; i < graphFiles.size(); i++)
			{
				try
				{
					File graphFile = graphFiles.get(i);
					
					Image image = ImageIO.read(graphFile);
					ImageIcon imgIcon = new ImageIcon();
					
					imgIcon.setImage(image.getScaledInstance(SMALL_GRAPH_WIDTH, SMALL_GRAPH_HEIGHT, Image.SCALE_DEFAULT));
					JLabel label = new JLabel(imgIcon);
					label.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
					label.addMouseListener(this);
					
					graphLabels.add(label);
					graphVizPanel.add(label);
				}
				catch(Exception ex)
				{
					logger.error(ex, ex);
				}
			}
		}
		
		drawGraphs();
	}
	
	@Override
	public void actionPerformed(ActionEvent event) 
	{
		if (event.getSource() == treeRadioBtn || event.getSource() == graphRadioBtn)
		{
			displayResult();
		}
	}

	@Override
	public void mouseClicked(MouseEvent event) 
	{
		int index = graphLabels.indexOf(event.getSource());
		
		if (index == -1)
			return;
		
		File graphFile = graphFiles.get(index);
		
		new GraphJFrame(graphFile);
	}

	@Override
	public void mouseEntered(MouseEvent arg0) 
	{
		setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
	}

	@Override
	public void mouseExited(MouseEvent arg0) 
	{
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
	}
	@Override
	public void componentHidden(ComponentEvent arg0) {
	}

	@Override
	public void componentMoved(ComponentEvent arg0) {
	}

	@Override
	public void componentResized(ComponentEvent arg0) 
	{
		drawGraphs();
	}

	@Override
	public void componentShown(ComponentEvent arg0) {
	}
	
	class GraphJFrame extends JFrame
	{
		private File graphFile;
		private JLabel label;
		private ImageIcon imgIcon;
		
		public GraphJFrame(File graphFile)
		{
			this.graphFile = graphFile;
			
			this.setTitle(graphFile.getAbsolutePath());
			
			showGraph();
			
			this.setSize(1000, 1000);
			this.setVisible(true);
		}
		
		private void showGraph()
		{
			JPanel graphPanel = new JPanel();
			JScrollPane graphView = new JScrollPane(graphPanel);
			
			graphPanel.setLayout(new BorderLayout());
			
			imgIcon = new ImageIcon(graphFile.getAbsolutePath());
			
			label = new JLabel(imgIcon);
			graphPanel.add(label, BorderLayout.CENTER);
			
			add(graphView);
		}
	}
		  
}
